﻿using System;
using System.Xml;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using SdmxMl.Common;
using SdmxMl.Helper;

namespace SdmxMl.Structure
{
    #region Class CoreRepresentationReference

    /// <summary>Codelist artefact reference Information </summary>
    public class CoreRepresentationReference : ArtefactRefBase
    {
        #region Internal Members


        #endregion //Internal Members

        #region Construction

        public CoreRepresentationReference()
        {
        }

        public CoreRepresentationReference(XmlNode nodeArtefact, SdmxNamespaceManager nsmgr)
        {
           
            if (nsmgr.VersionSdmx == SdmxVersion.SDMX_20)
            {
                Id = Xmlhelper.GetAtt(nodeArtefact, "coreRepresentation");
                Version = Xmlhelper.GetAtt(nodeArtefact, "coreRepresentationVersion");
                AgencyId = Xmlhelper.GetAtt(nodeArtefact, "coreRepresentationAgency");
            }
            else
            {
                string query = "./structure:CoreRepresentation/structure:Enumeration/Ref";
                XmlNode ndCoreRef = nodeArtefact.SelectSingleNode(query, nsmgr);
                if (ndCoreRef != null)
                {
                    AgencyId = Xmlhelper.GetAtt(ndCoreRef, "agencyID");
                    Id = Xmlhelper.GetAtt(ndCoreRef, "id");
                    Version = Xmlhelper.GetAtt(ndCoreRef, "version");
                }
                else
                {
                    // Try via URN
                    query = "./structure:CoreRepresentation/structure:Enumeration/URN";
                    ndCoreRef = nodeArtefact.SelectSingleNode(query, nsmgr);
                    if (ndCoreRef != null)
                    {
                        string urn = UrnParser.UrnSdmx_21_to_20(ndCoreRef.InnerText);
                        UrnParser p = new UrnParser(urn);
                        AgencyId = p.AgencyId;
                        Id = p.ArtefactId;
                        Version = p.Version;
                    }
                }
            }
        }

        public CoreRepresentationReference Clone()
        {
            CoreRepresentationReference c = new CoreRepresentationReference();
            c.Id = Id;
            c.AgencyId = AgencyId;
            c.Version = Version;
            return c;
        }


        #endregion //Construction

        #region XML Representation

        public void WriteXml(XmlTextWriter xw)
        {
            Xmlhelper.WriteAttributeIfExist(xw, "coreRepresentation", Id);
            if (Version != "1.0")
                Xmlhelper.WriteAttributeIfExist(xw, "coreRepresentationVersion", Version);
            Xmlhelper.WriteAttributeIfExist(xw, "coreRepresentationAgency", AgencyId);
        }

        public void WriteXml_21(XmlTextWriter xw, string prefix, TextFormatType tf)
        {
            if (tf.TextType != TextTypeType.Undefined || IsFilled)
            {
                xw.WriteStartElement(prefix, "CoreRepresentation", null);

                // Text Format only if no codelist ref
                if (tf.TextType != TextTypeType.Undefined && ! IsFilled)
                    tf.WriteXml(xw, prefix, "TextFormat");

                if (IsFilled)
                {
                    xw.WriteStartElement(prefix, "Enumeration", null);
                    xw.WriteStartElement("Ref");
                    Xmlhelper.WriteAttributeIfExist(xw, "agencyID", AgencyId);
                    Xmlhelper.WriteAttributeIfExist(xw, "id", Id);
                    if (Version != "1.0")
                        Xmlhelper.WriteAttributeIfExist(xw, "version", Version);
                    xw.WriteEndElement();
                    xw.WriteEndElement(); 
                }
                xw.WriteEndElement(); 
            }
        }

        #endregion //XMl Representation

    }
    #endregion


    /// <summary>
    /// ConceptType specifies the information provided for a single concept. 
    /// This includes a name, as element content, and an ID. It is possible to use the uri 
    /// field to point to the location of an SDMX-ML Structure message which contains a more 
    /// detailed version of the concept. (This is termed an "external reference".) 
    /// If an external reference is being made, the isExternalReference attribute must be set 
    /// to "true". In this case, all details of the concept are assumed to be found externally, 
    /// and inline characteristics provided through child elements and the coreRepresentation 
    /// and coreRepresentationAgency attributes are to be ignored. The coreRepresentation and 
    /// coreRepresentationAgency attributes can identify a codelist which is a default 
    /// representation of the concept. Uncoded default representations (or information about 
    /// the textual aspects of coded default representations) can be provided with the 
    /// TextFormat child element of the concept. Semantic relationships between concepts 
    /// which occur within a single concept scheme can be captured with the parent and 
    /// parentAgency attributes - these identify the concept of which the current concept 
    /// is a qualification (in the ISO 11179 sense) or subclass. When used outside of a 
    /// containing ConceptScheme, these attributes may be ignored. If a coreRepresentation 
    /// and core RepresentationAgency are not provided, but are provided in the indicated 
    /// parent, then the default representation is inherited from the specified parent concept. 
    /// Note that all concepts within a concept scheme must be uniquely identified by their 
    /// id - each concept scheme has only one agency for all its concepts. The agency attribute 
    /// here is provided for backward-compatibility with version 1.0 of the standards, and it 
    /// must not be used for concepts which are child elements of a concept scheme.
    /// </summary>
    public class ConceptType : BaseArtefact, ISdmxHierarchyListItem
    {
        #region Properties

        /// <summary>SDMX 1.0 Globals </summary>
        public string GlobalAgencyId { get; set; }

        /// <summary>Simple hierarchy inside org is possible </summary>
        public string Parent { get; set; }
        public bool IsExternalReference { get; set; }
        public string Urn { get; set; }
        public string Uri { get; set; }

        /// <summary>Associated codelist and Format type </summary>
        public CoreRepresentationReference CoreRepresentation { get; set; }
        public TextFormatType TextFormat { get; set; }

        /// <summary>SDMX 1.0 Globals </summary>
        private string _globalVersion;
        public string GlobalVersion
        {
            get { return _globalVersion; }
            set 
            { 
                _globalVersion = value;
                if (string.IsNullOrEmpty(_globalVersion))
                    _globalVersion = "1.0";
            }
        }

        // No use for flat hierarchy
        public IHierarchyManage InnerHierarchy
        {
            get { return null; }
        }

        /// <summary>Helper for Context info explanations</summary>
        public string ContextInfo
        {
            get
            {
                string description = Description.IsEmpty ? string.Empty : Description.ToString();
                string contextInfo = AnnotationList.GetTextOfAnnotationType("CONTEXT");
                return contextInfo.Length > 0 ? contextInfo : description;
            }
        }

        #endregion

        #region Construction

        private void Init()
        {
            TextFormat = new TextFormatType();
            CoreRepresentation = new CoreRepresentationReference();
        }

        public ConceptType()
        {
            Init();
        }

        public ConceptType(XmlNode nodeArtefact, SdmxNamespaceManager nsmgr) 
            : base(nodeArtefact, nsmgr)
        { 
            Init();

            IsExternalReference = Xmlhelper.GetAtt(nodeArtefact, "isExternalReference").ToLower() == "true";

            Urn = Xmlhelper.GetAtt(nodeArtefact, "urn");
            Uri = Xmlhelper.GetAtt(nodeArtefact, "uri");

            CoreRepresentation = new CoreRepresentationReference(nodeArtefact, nsmgr);

            if (nsmgr.VersionSdmx == SdmxVersion.SDMX_20)
            {
                Parent = Xmlhelper.GetAtt(nodeArtefact, "parent");

                // For SDMX 1.0 
                GlobalAgencyId = Xmlhelper.GetAtt(nodeArtefact, "agencyID");
                GlobalVersion = Xmlhelper.GetAtt(nodeArtefact, "version");

                TextFormat = new TextFormatType(nodeArtefact, nsmgr);
                TextFormatHelperForSdmx21Mimic tfmimic = new TextFormatHelperForSdmx21Mimic(TextFormat, this.AnnotationList);
                tfmimic.RetrieveFormXmlByAnnotation();

                //TEMP SILC change parent for flag
                //if (Id.Substring(Id.Length - 2) == "_F")
                    //Parent = Id.Substring(0, Id.Length - 2);

            }
            else // SDMX 2.1
            {
                // Parent given as node
                string query = "./structure:Parent/Ref";
                XmlNode ndParent = nodeArtefact.SelectSingleNode(query, nsmgr);
                if (ndParent != null)
                    Parent = Xmlhelper.GetAtt(ndParent, "id");

                // textFormat is under CoreRepresentation also
                query = "./structure:CoreRepresentation";
                XmlNode ndTF = nodeArtefact.SelectSingleNode(query, nsmgr);
                if (ndTF != null)
                    TextFormat = new TextFormatType(ndTF, nsmgr);
            }

            /*//TO REMOVE
            Annotation ac = AnnotationList.GetAnnotationType("CAI");
            if (ac != null)
                AnnotationList.Remove(ac);
            ac = AnnotationList.GetAnnotationType("cai");
            if (ac != null)
                AnnotationList.Remove(ac);
            */

        }
        #endregion

        #region Clone

        public ISdmxHierarchyListItem Clone()
        {
            ConceptType c = new ConceptType();
            c.Id = Id;
            c.Name = Name.Clone();
            c.Description = Description.Clone();
            c.Uri = Uri;
            c.Urn = Urn;
            c.TextFormat = new TextFormatType(this.TextFormat);
            c.CoreRepresentation = CoreRepresentation.Clone();

            return c;
        }
        #endregion


        #region XML serialize
        
        public void WriteXml(XmlTextWriter xw, string prefix, string tag)
        {
            xw.WriteStartElement(prefix, tag, null);

            if (SdmxNamespaceManager.SdmxTarget == SdmxVersion.SDMX_21)
            {
                Xmlhelper.WriteAttributeIfExist(xw, "urn", Urn);
                Xmlhelper.WriteAttributeIfExist(xw, "uri", Uri);
                // value required for Id
                xw.WriteAttributeString("id", Id);

                // Annotations at start
                AnnotationList.WriteXml(xw, "common", null);
                Name.WriteXml(xw, prefix, "Name");
                Description.WriteXml(xw, prefix, "Description");
                if (string.IsNullOrEmpty(Parent) == false)
                {
                    xw.WriteStartElement(prefix, "Parent", null);
                    xw.WriteStartElement("Ref");
                    xw.WriteAttributeString("id", Parent);
                    xw.WriteEndElement();
                    xw.WriteEndElement();
                }

                CoreRepresentation.WriteXml_21(xw, prefix, TextFormat);
            }
            else // SDMX 2.0
            {
                // value required
                xw.WriteAttributeString("id", Id);
                if (Version != "1.0")
                    Xmlhelper.WriteAttributeIfExist(xw, "version", Version);

                Xmlhelper.WriteAttributeIfExist(xw, "uri", Uri);
                Xmlhelper.WriteAttributeIfExist(xw, "urn", Urn);

                Xmlhelper.WriteAttributeIfExist(xw, "parent", Parent);
                if (IsExternalReference)
                    xw.WriteAttributeString("isExternalReference", IsExternalReference.ToString().ToLower());
                CoreRepresentation.WriteXml(xw);

                Name.WriteXml(xw, prefix, "Name");
                Description.WriteXml(xw, prefix, "Description");

                // Text Format
                TextFormat.WriteXml(xw, prefix, "TextFormat");

                // Annotations & SDMX 2.1 mimic
                TextFormatHelperForSdmx21Mimic tfmimic = new TextFormatHelperForSdmx21Mimic(TextFormat, this.AnnotationList);
                tfmimic.PersistToXmlByAnnotation(xw, prefix, null);
            }

            xw.WriteEndElement();
        }
        #endregion

        #region Tree Representation

        public override TreeNode FillNode(TreeNode parentNode)
        {
            TreeNode t = base.FillNode(parentNode);

            return t;
        }
        #endregion

        #region String Representation

        public override string ToString()
        {
            string txt = Id;
            if (Name.ToString() != MultiLang.UndefinedText)
                txt += " - " + Name.ToString();
            return txt;
        }
        #endregion
    }

    #region Concept list container

    public class ConceptList : FlatHierarchicalList
    {
        public ConceptList()
            : base("Code", "Description")
        {
        }

        public override ISdmxHierarchyListItem CreateNewItem()
        {
            return new ConceptType();
        }

        public override ISdmxHierarchyListItem CreateNewItem(XmlNode nd, SdmxNamespaceManager nsmgr)
        {
            return new ConceptType(nd, nsmgr);
        }

        public override string ToString()
        {
            return "Concepts";
        }
    }
    #endregion

}
